package com.kexio.auth.context;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import com.kexio.auth.config.TenantModeProperties;
import com.kexio.auth.dto.UserAuthInfo;
import com.kexio.auth.util.AuthContextUtils;

import jakarta.annotation.PostConstruct;

/**
 * 租户上下文解析器 - 避免循环依赖
 * 
 * 解决租户上下文获取过程中的循环依赖问题：
 * 1. 提供单一的租户ID获取入口
 * 2. 避免 AuthContextUtils 与 CacheKeyManager 之间的循环调用
 * 3. 规范化租户ID获取的优先级逻辑
 * 4. 提供安全的降级处理机制
 * 
 * 获取优先级：
 * 1. TenantContextHolder（ThreadLocal）
 * 2. 当前用户信息中的租户ID
 * 3. 配置的默认租户ID
 * 4. 系统默认值 "default"
 * 
 * @author Kexio Team
 * @since 1.0.0
 */
@Component
public class TenantContextResolver {
    
    private static final Logger logger = LoggerFactory.getLogger(TenantContextResolver.class);
    
    private static final String SYSTEM_DEFAULT_TENANT = "default";
    
    @Autowired
    private TenantModeProperties tenantProperties;
    
    private volatile boolean initialized = false;
    
    @PostConstruct
    public void init() {
        this.initialized = true;
        logger.info("🏢 TenantContextResolver 初始化完成: multiTenant={}, defaultTenant={}", 
                   isMultiTenant(), getDefaultTenantId());
    }
    
    /**
     * 安全获取当前租户ID - 避免循环调用
     * 
     * @return 当前有效的租户ID
     */
    public String getCurrentTenantId() {
        if (!initialized) {
            logger.warn("TenantContextResolver 未初始化，返回系统默认租户");
            return SYSTEM_DEFAULT_TENANT;
        }
        
        try {
            // 1. 优先从 ThreadLocal 获取（显式设置的租户）
            String tenantId = TenantContextHolder.getCurrentTenantId();
            if (StringUtils.hasText(tenantId) && !SYSTEM_DEFAULT_TENANT.equals(tenantId)) {
                logger.debug("从 TenantContextHolder 获取租户ID: {}", tenantId);
                return normalizeTenantId(tenantId);
            }
            
            // 2. 从当前用户信息获取（避免循环调用 AuthContextUtils 的方法）
            tenantId = extractTenantFromCurrentUser();
            if (StringUtils.hasText(tenantId) && !SYSTEM_DEFAULT_TENANT.equals(tenantId)) {
                logger.debug("从用户信息获取租户ID: {}", tenantId);
                return normalizeTenantId(tenantId);
            }
            
            // 3. 使用配置的默认租户
            tenantId = getDefaultTenantId();
            logger.debug("使用默认租户ID: {}", tenantId);
            return normalizeTenantId(tenantId);
            
        } catch (Exception e) {
            logger.error("获取租户ID失败，返回系统默认值", e);
            return SYSTEM_DEFAULT_TENANT;
        }
    }
    
    /**
     * 从当前用户提取租户ID - 避免循环调用
     */
    private String extractTenantFromCurrentUser() {
        try {
            // 直接从 AuthContextUtils 获取，避免循环依赖
            UserAuthInfo userInfo = AuthContextUtils.getCurrentUser();
            return userInfo != null ? userInfo.getTenantId() : null;
        } catch (Exception e) {
            logger.debug("从用户信息获取租户ID失败: {}", e.getMessage());
            return null;
        }
    }
    
    /**
     * 获取配置的默认租户ID
     */
    private String getDefaultTenantId() {
        try {
            return tenantProperties != null && StringUtils.hasText(tenantProperties.getDefaultTenant()) 
                ? tenantProperties.getDefaultTenant() 
                : SYSTEM_DEFAULT_TENANT;
        } catch (Exception e) {
            logger.debug("获取配置默认租户失败: {}", e.getMessage());
            return SYSTEM_DEFAULT_TENANT;
        }
    }
    
    /**
     * 检查是否为多租户模式
     * 
     * @return true 表示多租户模式，false 表示单租户模式
     */
    public boolean isMultiTenant() {
        try {
            return initialized && 
                   tenantProperties != null && 
                   tenantProperties.isEnabled();
        } catch (Exception e) {
            logger.debug("检查多租户模式失败: {}", e.getMessage());
            return false;
        }
    }
    
    /**
     * 规范化租户ID
     * 
     * @param tenantId 原始租户ID
     * @return 规范化后的租户ID
     */
    private String normalizeTenantId(String tenantId) {
        if (!StringUtils.hasText(tenantId)) {
            return SYSTEM_DEFAULT_TENANT;
        }
        
        String trimmed = tenantId.trim();
        
        // 基本验证
        if (trimmed.length() > 50) {
            logger.warn("租户ID过长，使用默认值: {}", trimmed);
            return SYSTEM_DEFAULT_TENANT;
        }
        
        // 移除危险字符
        String normalized = trimmed.replaceAll("[^a-zA-Z0-9_-]", "_");
        
        if (normalized.isEmpty()) {
            return SYSTEM_DEFAULT_TENANT;
        }
        
        return normalized;
    }
    
    /**
     * 设置当前租户ID（线程安全）
     * 
     * @param tenantId 租户ID
     */
    public void setCurrentTenantId(String tenantId) {
        try {
            if (StringUtils.hasText(tenantId)) {
                String normalizedTenantId = normalizeTenantId(tenantId);
                TenantContextHolder.setCurrentTenantId(normalizedTenantId);
                logger.debug("设置当前租户ID: {}", normalizedTenantId);
            } else {
                TenantContextHolder.clearTenantContext();
                logger.debug("清除当前租户ID");
            }
        } catch (Exception e) {
            logger.error("设置租户ID失败: tenantId={}", tenantId, e);
        }
    }
    
    /**
     * 清除当前租户上下文
     */
    public void clearTenantContext() {
        try {
            TenantContextHolder.clearTenantContext();
            logger.debug("租户上下文已清除");
        } catch (Exception e) {
            logger.error("清除租户上下文失败", e);
        }
    }
    
    /**
     * 在指定租户上下文中执行操作
     * 
     * @param tenantId 租户ID
     * @param action 要执行的操作
     * @param <T> 返回值类型
     * @return 操作结果
     * @throws Exception 操作异常
     */
    public <T> T executeWithTenant(String tenantId, java.util.concurrent.Callable<T> action) throws Exception {
        String originalTenantId = getCurrentTenantId();
        try {
            setCurrentTenantId(tenantId);
            return action.call();
        } finally {
            if (StringUtils.hasText(originalTenantId) && !SYSTEM_DEFAULT_TENANT.equals(originalTenantId)) {
                setCurrentTenantId(originalTenantId);
            } else {
                clearTenantContext();
            }
        }
    }
    
    /**
     * 在指定租户上下文中执行操作（无返回值）
     * 
     * @param tenantId 租户ID
     * @param action 要执行的操作
     */
    public void executeWithTenant(String tenantId, Runnable action) {
        String originalTenantId = getCurrentTenantId();
        try {
            setCurrentTenantId(tenantId);
            action.run();
        } finally {
            if (StringUtils.hasText(originalTenantId) && !SYSTEM_DEFAULT_TENANT.equals(originalTenantId)) {
                setCurrentTenantId(originalTenantId);
            } else {
                clearTenantContext();
            }
        }
    }
    
    /**
     * 验证租户ID的有效性
     * 
     * @param tenantId 租户ID
     * @return 是否有效
     */
    public boolean isValidTenantId(String tenantId) {
        if (!StringUtils.hasText(tenantId)) {
            return false;
        }
        
        String trimmed = tenantId.trim();
        
        // 检查长度
        if (trimmed.length() < 1 || trimmed.length() > 50) {
            return false;
        }
        
        // 检查格式：只允许字母、数字、下划线、中划线
        return trimmed.matches("^[a-zA-Z0-9_-]+$");
    }
    
    /**
     * 获取用于日志显示的租户ID
     * 
     * @return 租户ID，单租户模式返回 "[SINGLE_TENANT]"
     */
    public String getTenantIdForLogging() {
        if (!isMultiTenant()) {
            return "[SINGLE_TENANT]";
        }
        
        String tenantId = getCurrentTenantId();
        return StringUtils.hasText(tenantId) ? tenantId : "[UNKNOWN]";
    }
    
    /**
     * 获取租户上下文摘要信息
     * 
     * @return 上下文摘要
     */
    public String getContextSummary() {
        try {
            return String.format("TenantContext{mode=%s, current=%s, initialized=%s}",
                               isMultiTenant() ? "MULTI" : "SINGLE",
                               getTenantIdForLogging(),
                               initialized);
        } catch (Exception e) {
            return "TenantContext{error=" + e.getMessage() + "}";
        }
    }
    
    /**
     * 健康检查
     * 
     * @return 是否健康
     */
    public boolean isHealthy() {
        try {
            return initialized && 
                   tenantProperties != null &&
                   StringUtils.hasText(getCurrentTenantId());
        } catch (Exception e) {
            logger.debug("租户上下文健康检查失败", e);
            return false;
        }
    }
}
